Win32API【1】 |
您所在的位置:网站首页 › delphi 窗口句柄 › Win32API【1】 |
本节是个大难关,一定要多看,多敲代码理解
0. 关于在DevC++上的一些准备新建项目修改项目属性项目的重要性
教程1. 初识WinMain函数2. 让系统知道我们要弄一个窗口——注册窗口类3. 创建窗口——CreateWindow函数4. 萌新噩梦:消息循环与回调函数创建消息循环绑定回调函数
完整代码示例
所有代码文件均已放到蓝奏云网盘,下载解压即可运行! WIN32API示例 (DEVC++) 密码:dgaf
Windows.h 囊括了WinAPI几乎所有的函数与宏定义,然而实际上源码只有200来行 ,为什么? 各位C语言党不要担心,Win32API 是用纯C写的,没有C++的晦涩语法 (毕竟C++党都去MFC与QT了),虽然是老工具,可是放眼现在照样有人用 本系列教程我们不用VC (VC的确方便啊,该链的库直接唰唰唰帮你弄好,不用怕什么链接错误又要修改项目属性之类的) ,使用小熊猫 DevC++ 来完成Windows编程之旅! 0. 关于在DevC++上的一些准备 新建项目打开小熊猫 DevC++,文件->新建->新建项目->选择空项目 之后如果要打开项目,只需 点击.dev文件 即可 打开项目管理,修改项目属性:将类型改成 Win32图形界面程序(GUI) DevC++是支持单文件编译的 ,有人说,我们可以只用一个.c文件来做啊,为什么要拐弯抹角建一个项目呢? 其实,学到后面你就会发现,如果使用单个.c文件,管理资源很不方便 (例如 头文件,资源文件,regex文件等等) ,要处理这些麻烦问题最后还不是要弄项目? 所以,我想对学C的萌新说一句,早学项目早受益,之后我们还会涉及大量的项目管理 教程 1. 初识WinMain函数我们需要抛弃陪伴我们萌新很久的main函数,改成WinMain函数 int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, LPSTR lpCMDline, int nCMDshow) { }你会发现我们需要写这么大一串!用main函数不就更好? 事实上,我们只需要用第一个参数 hinstance , 然后把它改成: int WINAPI WinMain(HINSTANCE hin,HINSTANCE,LPSTR,int) { }这样就简洁多了,关于WinMain的参数,我们只需要理解第一个参数 hinstance hinstance :应用程序当前实例的句柄。 另外,这个hinstance是系统给我们的,不用我们瞎操心,照着用就行 就好像医院妇产科,系统都会给每一个新生儿一个hinstance,不然没hinstance很容易把别人家孩子搞混。hinstance的存在也正是如此,它可以唯一标识应用程序 2. 让系统知道我们要弄一个窗口——注册窗口类首先,我们需要让系统知道我们要弄窗口,在WinMain函数写上 // WNDCLASS 窗口类信息,是个结构体 WNDCLASS wc = {}; wc.hInstance = hin; //实例句柄 wc.lpszClassName = "MY_Window"; //窗口类名 RegisterClass(&wc); //注册窗口 // RegisterClass() 注册窗口类 // 接受一个 WNDCLASS 的指针 // 必须通过这一步, 窗口才能注册成功你会发现,我们要向系统传一个叫 “WNDCLASS” 窗口类 的东西,这个东西是什么呢? 我们在上面讲到,Hinstance实例句柄作为指向一个应用程序实例的东西,它不仅包括了窗口,还包括该应用程序的图片音乐等等很多东西,包这么多东西,如果我在外面,只是找里面的窗口岂不是很麻烦? 窗口类(WNDClass) 于是就出来了,你可以理解为 一个程序里面所有窗口的集合 窗口类毕竟是一个集合啊!那我们怎么表示单个窗口? 窗口句柄(HWND) 出来了,实际上是一个窗口在系统的唯一ID 下面是三者的关系: 之后我们填完WNDCLASS结构体,就可以通过 RegisterClass函数 告诉系统我们要弄窗口了。 3. 创建窗口——CreateWindow函数我们注册窗口类之后,就可以 真正弄个窗口 了 // CreateWindow 创建窗口,返回一个窗口句柄 HWND hwnd = CreateWindow( "M_CLASS", //窗口类名,要和上文的 lpszClassName 相同,否则返回NULL "我的第一个程序", //窗口标题 WS_OVERLAPPEDWINDOW|WS_VISIBLE, //窗口样式 0, //窗口左上角横坐标 0, //窗口左上角纵坐标 640, //窗口宽度 480, //窗口高度 NULL, //父窗口 (HWND) NULL, //菜单句柄 (HMENU) hin, //实例句柄 (HINSTANCE) ,不填会返回NULL NULL //附加参数 );可能这是C语言萌新见过的最长的函数,开场11个参数,而且都要填! 但是,我们最常用的也还是那几个参数罢了! 这里说明一下第3个参数窗口样式,第三个参数指定了我们窗口是咋样的 WS_OVERLAPPEDWINDOW 这个包括了一个常见窗口所需的所有样式,直接记就行了! WS_VISIBLE 这个指定我们的窗口是否可见 更多样式可以参考这位大神的文章: tanyufeng_521:Windows窗口风格详细解释 创建完之后,我们的程序就差一步即可大功告成,也是基础中最难的一步:消息循环! 4. 萌新噩梦:消息循环与回调函数这里先放图 WinAPI的窗口难道只是创建就行了吗?大错特错! 你会发现,窗口会一闪而过!程序也完成任务回家了。 如何才能让窗口一直显示? 这个时候,消息循环 的重要作用就很好的彰显出来了! //消息循环的构建 MSG msg = {}; //消息结构体 while(GetMessage(&msg,NULL,0,0)>0) // 如果没有发生错误,且收到了任意消息... { ::TranslateMessage(&msg); // 翻译消息,将消息中的键盘码转换为对应的字符 ::DispatchMessage(&msg); // 派发消息,调用 CallBackFunc 回调函数处理消息 }借助这个循环,程序就可以一直发出消息,阻止程序自身退出 只要用户不按窗口右上角的退出按钮!程序就会一直运行! 问题是,当你把这个循环打上去之后,你就会发现,窗口连影都没有 那么,我们可以使用 DefWindowProc() 返回一个窗口 但是,如何用呢?我们发现,把 DefWindowProc() 放进while循环里竟然不起作用! 原来,是我们没有处理 DefWindowProc 返回的窗口! 那么我们应该如何处理呢? 你会发现,我们少讲了什么… 绑定回调函数没错,就是 回调函数 (CallBackFunction) 我们可以使用回调函数,对 DefWindowProc 返回的窗口进行处理 第一次看 回调 (CallBack) 这个概念的时候萌新肯定会不理解,其实在生活中回调是触手可及的! 就比如说,你现在肚子很饿,直接下馆子,当你点完餐以后,你就会不停的询问服务员什么时候可以上菜,我快饿死了!!! 这时候,服务员肯定会不停地告诉你上菜时间! 不停的操作与获得更新结果,就是回调的概念 有了回调函数,我们就可以保证窗口一直显示! //回调函数, 返回一个窗口 LRESULT CALLBACK CallBackFunc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) { // hwnd 从主函数获得的窗口句柄 // msg 从主函数的消息循环获得的消息 // wParam 附加参数1 // lParam 附加参数2 // C语言Review: // switch用于对一个整数进行判断,并跳到相应的case语句块 // 会一直执行直至break或switch语句块的末尾 // 所以写完一个case 随手加break是一个必须养成的习惯 // 不然会执行意想不到的结果 switch(msg) //对msg进行判断,进switch语句块 { case WM_DESTROY: //如果要退出 PostQuitMessage(0); //传递退出消息,终止主函数的消息循环 break; // 默认行为(什么都不做,就返回窗口) // 这个地方,很多萌新都容易漏,导致窗口不显示又退不出循环,注意一下 default: return DefWindowProc(hwnd,msg,wParam,lParam); } }代码中我们使用了switch语句,对回调函数的msg消息进行处理 然后再根据消息进行操作或返回窗口 高一的时候我开始学做窗口,就是被这消息循环难住了,导致当时还要死记硬背 (当时没理解,只好死记硬背,现在看来完全没必要,果真编程还是注重思维培养的) 消息循环还是得多看,如果你能理解上面那张流程图,那么这样的框架你也能唾手可得 经历了那么多曲折,现在我们终于可以做一个窗口了。 我是DGAF,我们下个教程见 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |